﻿#include "QuadTree.h"
#include "SweptAABB.h"
#include "Object.h"
#include "StaticObject.h"
#include "Box.h"
QuadTree::QuadTree(void)
{
}

QuadTree::QuadTree(Box* b)
{
	_box = b;
	_qtWidth = b->getRight();
	_qtHeight = b->getBottom();
}

QuadTree::~QuadTree(void)
{
}

void QuadTree::insert(Object* obj)
{
	if(!isCover(_box, obj->getBox()))
		return;
	if(_listObject.size() < 5)
	{
		_listObject.push_back(obj);
		return;
	}

	if(_listQNode.size() == 0 && !split(obj->getBox()))		
	{
		_listObject.push_back(obj);
		return;
	}

	bool flat = false;
	for (QuadTree* node : _listQNode)
	{
		if(isCover(node->_box, obj->getBox()))
		{
			flat = true;
			node->insert(obj);
			break;
		}
	}
	if(!flat)
		_listObject.push_back(obj);
}

void QuadTree::insert(Box* box)
{
	if(!isCover(_box, box))
		return;
	if(_listBox.size() < 5)
	{
		_listBox.push_back(box);
		return;
	}
	if(_listQNode.size() == 0 && !split(box))		
	{
		_listBox.push_back(box);
		return;
	}

	bool flat = false;
	for (QuadTree* node : _listQNode)
	{
		if(isCover(node->_box, box))
		{
			flat = true;
			node->insert(box);
			break;
		}
	}
	if(!flat)
		_listBox.push_back(box);
}

void QuadTree::insert(StaticObject* st)
{
	if(!isCover(_box, st->getBox()))
		return;
	if(_listStaticObject.size() < 5)
	{
		_listStaticObject.push_back(st);
		return;
	}

	if(_listQNode.size() == 0 && !split(st->getBox()))		
	{
		_listStaticObject.push_back(st);
		return;
	}

	bool flat = false;
	for (QuadTree* node : _listQNode)
	{
		if(isCover(node->_box, st->getBox()))
		{
			flat = true;
			node->insert(st);
			break;
		}
	}
	if(!flat)
		_listStaticObject.push_back(st);
}

//lam cho tui một hàm
//tham so query là box.
//tra ve là các Object :D

bool QuadTree::split(Box* box)
{
	if(_box->_size.x * _box->_size.y < 100)
		return false;
	float subTop = _box->_position.y;
	float subLeft = _box->_position.x;
	float subW = _box->_size.x / 2;
	float subH = _box->_size.y / 2;
	if(subLeft < box->_position.x
		&& subLeft + subW > box->getRight()
		&& subTop < box->_position.y
		&& subTop + subH > box->getBottom())
	{
		QuadTree* I = new QuadTree(new Box(D3DXVECTOR2(subLeft, subTop), D3DXVECTOR2(subW, subH), D3DXVECTOR2(0, 0)));
		QuadTree* II = new QuadTree(new Box(D3DXVECTOR2(subLeft + subW, subTop), D3DXVECTOR2(subW, subH), D3DXVECTOR2(0, 0)));
		QuadTree* III = new QuadTree(new Box(D3DXVECTOR2(subLeft, subTop + subH), D3DXVECTOR2(subW, subH), D3DXVECTOR2(0, 0)));
		QuadTree* IV = new QuadTree(new Box(D3DXVECTOR2(subLeft + subW, subTop + subH), D3DXVECTOR2(subW, subH), D3DXVECTOR2(0, 0)));
		_listQNode.push_back(I);
		_listQNode.push_back(II);
		_listQNode.push_back(III);
		_listQNode.push_back(IV);
		return true;
	}
	return false;
}

list<Object*> QuadTree::query(Object* obj)
{
	list<Object*> lResult;
	if(!SweptAABB::checkAABB(_box, obj->getBox()))
		return lResult;
	for(Object* o : _listObject)
	{
		if(SweptAABB::checkAABB(o->getBox(), obj->getBox()) && o->getObjectType() != obj->getObjectType())
			lResult.push_back(o);
	}
	if(_listQNode.size() == 0)
		return lResult;
	for(QuadTree* n : _listQNode)
	{		
		list<Object*> tmp;
		tmp = n->query(obj);
		lResult.insert(lResult.end(), tmp.begin(), tmp.end());
	}
	return lResult;
}

list<Box*> QuadTree::query(Box* box)
{
	list<Box*> lResult;
	if(!SweptAABB::checkAABB(_box, box))
		return lResult;
	for(Box* b : _listBox)
	{
		if(SweptAABB::checkAABB(b, box))
			lResult.push_back(b);
	}
	if(_listQNode.size() == 0)
		return lResult;
	for(QuadTree* n : _listQNode)
	{		
		list<Box*> tmp;
		tmp = n->query(box);
		lResult.insert(lResult.end(), tmp.begin(), tmp.end());
	}
	return lResult;
}

void QuadTree::clear()
{
	_listObject.clear();
	for(QuadTree* qt : _listQNode)
	{		
		qt->clear();
	}
}

bool QuadTree::isCover(Box* b1, Box* b2)
{
	if(b1->_size.x == _qtWidth || b1->_size.y == _qtHeight)
	{
		if(b1->_position.x <= b2->_position.x
			&& b1->getRight() >= b2->getRight()
			&& b1->_position.y <= b2->_position.y
			&& b1->getBottom() >= b2->getBottom())
			return true;
	}
	else
		if(b1->_position.x < b2->_position.x
			&& b1->getRight() > b2->getRight()
			&& b1->_position.y < b2->_position.y
			&& b1->getBottom() > b2->getBottom())
			return true;
	return false;
}

list<StaticObject*> QuadTree::query_staticObj(Box* box)
{
	list<StaticObject*> lResult;
	if(!SweptAABB::checkAABB(_box, box))
		return lResult;

	for(StaticObject* o : _listStaticObject)
	{	
		if(SweptAABB::checkAABB(o->getBox(), box))
			lResult.push_back(o);
	}
	if(_listQNode.size() == 0)
		return lResult;
	for(QuadTree* n : _listQNode)
	{		
		list<StaticObject*> tmp;
		tmp = n->query_staticObj(box);
		lResult.insert(lResult.end(), tmp.begin(), tmp.end());
	}
	return lResult;
}

int QuadTree::count()
{
	int c = this->_listStaticObject.size();
	for (QuadTree* i : _listQNode)
	{
		c += i->count();
	}
	return c;
}

list<Object*> QuadTree::queryObject(Box* box)
{
	list<Object*> lResult;
	if(!SweptAABB::checkAABB(_box, box))
		return lResult;

	for(Object* o : _listObject)
	{	
		if(SweptAABB::checkAABB(o->getBox(), box))
			lResult.push_back(o);
	}
	if(_listQNode.size() == 0)
		return lResult;
	for(QuadTree* n : _listQNode)
	{		
		list<Object*> tmp;
		tmp = n->queryObject(box);
		lResult.insert(lResult.end(), tmp.begin(), tmp.end());
	}
	return lResult;
}

bool QuadTree::Exists(ObjectType id)
{
	for (Object * i: _listObject)
	{
		if(i->getObjectType() == DEBUG_GAME)
		{
			return true;
		}		
		for (QuadTree* i : _listQNode)
		{
			if(i->Exists(id))
				return true;
		}		
	}
	return false;
}
